package com.inno.thread.utils;

import java.util.Map;
import java.util.concurrent.*;

/**
 * Java并发工具类，同步屏障CyclicBarrier
 * 当多个线程全部到达屏障后，继续往后执行
 * （类比：所有汽车到达红绿灯后，变为绿灯，放行，所有车辆继续行驶）
 * 线程任务执行完毕后，进程没有停止，是因为我们使用了线程池去管理线程。
 *
 * @author: May
 * @date 2021/3/5
 */
public class TestCyclicBarrier {

    private static int sheetCount = 4;

    public static void main(String[] args) {
        BankWaterService bankWaterService = new BankWaterService();
        bankWaterService.count();
        System.out.println("主线程执行完毕");
    }

    private static class BankWaterService implements Runnable {
        /**
         * 创建4个屏障，处理完之后执行当前类的run方法
         */
        private CyclicBarrier barrier = new CyclicBarrier(4, this);

        /**
         * 假设有4个Sheet，所以只启动4个线程
         */
        private Executor executor = Executors.newFixedThreadPool(4);

        /**
         * 用来保存每个Sheet计算出来的银行流水结果
         */
        private ConcurrentHashMap<String, Integer> sheetBankWaterCount = new ConcurrentHashMap<>();


        @Override
        public void run() {
            int result = 0;
            // 计算总得银行流水
            for (Map.Entry<String, Integer> sheet : sheetBankWaterCount.entrySet()) {
                result += sheet.getValue();
            }
            sheetBankWaterCount.put("result", result);
            System.out.println("result = " + result);
        }

        public void count() {
            for (int i = 0; i < sheetCount; i++) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        // 计算当前Sheet的流水
                        sheetBankWaterCount.put(Thread.currentThread().getName(), 1);
                        try {
                            barrier.await();
                            System.out.println("---------------------");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (BrokenBarrierException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }

        }
    }
}
